﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.ServiceModel;
using System.Threading;
using System.Windows;
using System.Windows.Browser;
using TheGameClient.SoftwareUI.FeatureUI;
using TheGameClient.Webservices;

namespace TheGameClient
{
	public partial class App
	{
		#region static properties

		private static TheGameServiceClient _client;
		public static string TcpHost;
		public static int TcpPort;
		public static Guid InternalSessionId { get; set; }

		public static ulong MyGatewayId { get; set; }

		public static ulong MySystemId { get; set; }

		public static string Login { get; set; }
		public static string Password { get; set; }

		public static ulong MyCorporationId { get; set; }

		public static ulong MyRootDirectoryId { get; set; }

		public static List<SmallComputerSystem> MyKnownComputers { get; set; }

		public static string MyIP { get; set; }

		public static TheGameServiceClient Client
		{
			get
			{
				if (_client == null)
				{
					_client = new TheGameServiceClient();
					_client.RebootForHardwareChangeReceived += ClientRebootForHardwareChangeReceived;
				}
				//if (client.State != CommunicationState.Opened)
				//{
				//    throw new Exception("Connection lost.");
				//    //MessageBox.Show("The connection to the server has been lost. Perhaps the server is offline.\nPlease try to log in again in a few minutes.");
				//    //client = new U2SvcClient();
				//    //RootControl.ContentBorder.Child = new LoginScreen();
				//}
				//remove event handlers from generic methods
				//client.ResetAllEventHandlers();
				return _client;
			}
		}

		public static RootControl RootControl { get; private set; }

		public static int MyGatewayCpuSpeed { get; set; }

		public static int MyGatewayTotalMemory { get; set; }
		public static int MyGatewayBandwidth { get; set; }

		public static DateTime WorldTime { get; set; }

		public static void ServerError()
		{
			MessageBox.Show(
				"An error occured while communicating with the game server. The connection was lost. Please try to log in again in a few minutes.");
			RootControl.ContentBorder.Child = new LoginScreen();
		}

		#endregion

		public App()
		{
			Startup += ApplicationStartup;
			Exit += Application_Exit;
			UnhandledException += ApplicationUnhandledException;
			InternalSessionId = Guid.Empty;
			InitializeComponent();
		}

		public static void RegisterDynamicUI()
		{
			MasterUiFactory.Instance.RegisterProgramFactory(new SecSysUsernamePasswordControl().InterfaceId,
			                                                new SecurityUsernamePasswordUiFactory());
			MasterUiFactory.Instance.RegisterProgramFactory(new SecSysFingerprintControl().InterfaceId,
			                                                new SecurityFingerprintUiFactory());
			MasterUiFactory.Instance.RegisterProgramFactory(new SecSysRetinalScanControl().InterfaceId,
			                                                new SecurityRetinalScanUiFactory());
			MasterUiFactory.Instance.RegisterProgramFactory(new SecSysDnaScanControl().InterfaceId,
			                                                new SecurityDnaScanUiFactory());
			MasterUiFactory.Instance.RegisterProgramFactory(new SecSysPsecControl().InterfaceId, new SecurityPsecUiFactory());
			MasterUiFactory.Instance.RegisterProgramFactory(new SecSysTbpaControl().InterfaceId, new SecurityTbpaUiFactory());

			MasterUiFactory.Instance.RegisterProgramFactory(new FeatureFileSystemControl().InterfaceId,
			                                                new FeatureFileSystemUiFactory());
			MasterUiFactory.Instance.RegisterProgramFactory(new FeatureLogViewerControl().InterfaceId,
			                                                new FeatureLogViewerUiFactory());
			MasterUiFactory.Instance.RegisterProgramFactory(new FeatureMarketControl().InterfaceId,
			                                                new FeatureMarketUiFactory());
			MasterUiFactory.Instance.RegisterProgramFactory(new FeatureLocalChatControl().InterfaceId,
			                                                new FeatureLocalChatUiFactory());
			MasterUiFactory.Instance.RegisterProgramFactory(new FeatureMailControl().InterfaceId, new FeatureMailUiFactory());
			MasterUiFactory.Instance.RegisterProgramFactory(new FeatureBankingControl().InterfaceId,
			                                                new FeatureBankingControlUiFactory());
			MasterUiFactory.Instance.RegisterProgramFactory(new FeatureHardwareStorage().InterfaceId,
			                                                new FeatureHardwareStorageUiFactory());
			MasterUiFactory.Instance.RegisterProgramFactory(new FeatureAccountControl().InterfaceId,
			                                                new FeatureAccountControlUiFactory());
			MasterUiFactory.Instance.RegisterProgramFactory(new FeatureUsenetControl().InterfaceId,
			                                                new FeatureUsenetUiFactory());

			MasterUiFactory.Instance.RegisterProgramFactory(new ProgramRainbowTableAttack().InterfaceId,
			                                                new ProgramRainbowTableAttackFactory());
			MasterUiFactory.Instance.RegisterProgramFactory(new ProgramFingerprintSpoofer().InterfaceId,
			                                                new ProgramFingerprintSpooferFactory());
			MasterUiFactory.Instance.RegisterProgramFactory(new ProgramRetinalScanBypass().InterfaceId,
			                                                new ProgramRetinalScanBypassFactory());
			MasterUiFactory.Instance.RegisterProgramFactory(new ProgramDnaProfileBypass().InterfaceId,
			                                                new ProgramDnaProfileBypassFactory());
			MasterUiFactory.Instance.RegisterProgramFactory(new ProgramPsecBypass().InterfaceId, new ProgramPsecBypassFactory());
			MasterUiFactory.Instance.RegisterProgramFactory(new ProgramTbpaBypass().InterfaceId, new ProgramTbpaBypassFactory());

			MasterUiFactory.Instance.RegisterProgramFactory(new ProgramFileCopier().InterfaceId, new ProgramFileCopierFactory());
			MasterUiFactory.Instance.RegisterProgramFactory(new ProgramFileDeleter().InterfaceId,
			                                                new ProgramFileDeleterFactory());
			MasterUiFactory.Instance.RegisterProgramFactory(new ProgramFileCompressor().InterfaceId,
			                                                new ProgramFileCompressorFactory());
			MasterUiFactory.Instance.RegisterProgramFactory(new ProgramFileDecompressor().InterfaceId,
			                                                new ProgramFileDecompressorFactory());
			MasterUiFactory.Instance.RegisterProgramFactory(new ProgramFileEncrypter().InterfaceId,
			                                                new ProgramFileEncrypterFactory());
			MasterUiFactory.Instance.RegisterProgramFactory(new ProgramFileDecrypter().InterfaceId,
			                                                new ProgramFileDecrypterFactory());
			MasterUiFactory.Instance.RegisterProgramFactory(new ProgramRainbowTableCreator().InterfaceId,
			                                                new ProgramRainbowTableCreatorUiFactory());
			MasterUiFactory.Instance.RegisterProgramFactory(new ProgramLogDeleter().InterfaceId, new ProgramLogDeleterFactory());
			MasterUiFactory.Instance.RegisterProgramFactory(new ProgramLogUndeleter().InterfaceId,
			                                                new ProgramLogUndeleterFactory());

			MasterUiFactory.Instance.RegisterProgramFactory(new ProgramDigitizeFingerprint().InterfaceId,
			                                                new ProgramDigitizeFingerprintFactory());
			MasterUiFactory.Instance.RegisterProgramFactory(new ProgramDigitizeRetina().InterfaceId,
			                                                new ProgramDigitizeRetinaFactory());
			MasterUiFactory.Instance.RegisterProgramFactory(new ProgramDigitizeDNA().InterfaceId,
			                                                new ProgramDigitizeDNAFactory());
		}

		public static void ResetClient()
		{
			_client.Abort();
			_client.CloseCompleted += delegate
			{
				InternalSessionId = Guid.Empty;
				MyGatewayId = 0;
				MyKnownComputers.Clear();
				MySystemId = 0;
				MyCorporationId = 0;
				MyRootDirectoryId = 0;
				Login = null;
				Password = null;
				MyIP = null;
				_client = null;
			};
			_client.CloseAsync();
		}

		private static void ClientRebootForHardwareChangeReceived(object sender, AsyncCompletedEventArgs e)
		{
			RootControl.RebootDistortion.Completed += RebootDistortionCompleted;
			RootControl.RebootDistortion.Begin();
		}

		private static void RebootDistortionCompleted(object sender, EventArgs e)
		{
			RootControl.RebootDistortion.Completed -= RebootDistortionCompleted;
			_client.LogoutCompleted += ClientLogoutCompleted;
			_client.LogoutAsync(InternalSessionId, Login, Password);
		}

		private static void ClientLogoutCompleted(object sender, LogoutCompletedEventArgs e)
		{
			_client.LogoutCompleted -= ClientLogoutCompleted;
			InternalSessionId = Guid.Empty;
			_client.Abort();
			_client.CloseCompleted += ClientCloseCompleted;
			_client.CloseAsync();
		}

		private static void ClientCloseCompleted(object sender, AsyncCompletedEventArgs e)
		{
			_client.CloseCompleted -= ClientCloseCompleted;
			InternalSessionId = Guid.Empty;
			MyGatewayId = 0;
			MyKnownComputers.Clear();
			MySystemId = 0;
			MyCorporationId = 0;
			MyRootDirectoryId = 0;
			Login = null;
			Password = null;
			MyIP = null;
			_client = null;
			RootControl.ContentBorder.Child = new LoginScreen();
			RootControl.WaitAnim.Completed += WaitAnimCompleted;
			RootControl.WaitAnim.Begin();
		}

		private static void WaitAnimCompleted(object sender, EventArgs e)
		{
			RootControl.WaitAnim.Completed -= WaitAnimCompleted;
			RootControl.RebootDistortionBack.Begin();
		}

		private void ApplicationStartup(object sender, StartupEventArgs e)
		{
			if (!Current.IsRunningOutOfBrowser)
				RootVisual = new BrowserIntro();
			else
			{
				Current.CheckAndDownloadUpdateCompleted += OnCurrentOnCheckAndDownloadUpdateCompleted;
				Current.CheckAndDownloadUpdateAsync();
			}
		}

		private void OnCurrentOnCheckAndDownloadUpdateCompleted(object s, CheckAndDownloadUpdateCompletedEventArgs e)
		{
			if (e.UpdateAvailable)
			{
				RootVisual = new NewVersionDetected();
			}
			else if (e.Error is PlatformNotSupportedException)
			{
				RootVisual = new IncompatiblePlatform();
			}
			else
				RootControl = new RootControl();
			RootVisual = RootControl;
			RootControl.ContentBorder.Child = new LoginScreen();
		}

		private void Application_Exit(object sender, EventArgs e)
		{
			if (Current.IsRunningOutOfBrowser && (_client != null && _client.State == CommunicationState.Opened) &&
			    InternalSessionId != Guid.Empty)
			{
				Client.LogoutAsync(InternalSessionId, Login, Password);
				Thread.Sleep(2000);
			}
		}

		private void ApplicationUnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e)
		{
			//if (e.ExceptionObject is TargetInvocationException || e.ExceptionObject is EndpointNotFoundException || e.ExceptionObject is CommunicationObjectFaultedException)
			//    return;
			// If the app is running outside of the debugger then report the exception using
			// the browser's exception mechanism. On IE this will display it a yellow alert 
			// icon in the status bar and Firefox will display a script error.
			if (!Debugger.IsAttached)
			{
				// NOTE: This will allow the application to continue running after an exception has been thrown
				// but not handled. 
				// For production applications this error handling should be replaced with something that will 
				// report the error to the website and stop the application.
				e.Handled = true;
				Deployment.Current.Dispatcher.BeginInvoke(delegate { ReportErrorToDOM(e); });
			}
			else
			{
				throw e.ExceptionObject;
			}
		}

		private void ReportErrorToDOM(ApplicationUnhandledExceptionEventArgs e)
		{
			try
			{
				string errorMsg = e.ExceptionObject.Message + e.ExceptionObject.StackTrace;
				errorMsg = errorMsg.Replace('"', '\'').Replace("\r\n", @"\n");

				HtmlPage.Window.Eval("throw new Error(\"Unhandled Error in Silverlight Application " + errorMsg + "\");");
			}
			catch (Exception)
			{
			}
		}
	}
}

namespace TheGameClient.Webservices
{
	public partial class TheGameServiceClient
	{
		public void ResetAllEventHandlers()
		{
			//ObtainEntitiesByTypeCompleted = null;
			//ObtainEntitiesByTypeListCompleted = null;
			//ObtainEntityCompleted = null;
			//PersistEntityCompleted = null;
			//DeleteEntityCompleted = null;
			ExecuteProgramCompleted = null;

			//Connect_ConnectToSystemCompleted = null;
			//Connect_DisconnectFromSystemCompleted = null;

			//FieldInfo[] fields = GetType().GetFields(BindingFlags.Static | BindingFlags.NonPublic);
			//foreach (FieldInfo fi in fields)
			//{
			//    if (fi.Name.Contains("Completed"))
			//    {
			//        object obj = fi.GetValue(this);
			//        PropertyInfo pi = GetType().GetProperty("Events", BindingFlags.NonPublic | BindingFlags.Instance);
			//        var list = pi.GetValue(this, null);
			//        //list.RemoveHandler(obj, list[obj]);
			//    }
			//}
		}
	}
}